<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>智能HTML卡片转图片工具 | 个人简介 | 知识卡片</title>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #f4f7f9;
            color: #333;
            display: flex;
            flex-direction: column;
            align-items: center;
        }
        .container {
            background-color: #fff;
            padding: 30px;
            border-radius: 8px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
            width: 100%;
            max-width: 800px;
            margin-bottom: 20px;
        }
        h1 {
            text-align: center;
            color: #2c3e50;
            margin-bottom: 30px;
        }
        label {
            display: block;
            margin-bottom: 8px;
            font-weight: 600;
            color: #555;
        }
        textarea,
        input[type="text"] {
            width: calc(100% - 22px); /* Full width minus padding and border */
            padding: 10px;
            margin-bottom: 20px;
            border: 1px solid #ddd;
            border-radius: 5px;
            font-size: 14px;
            box-sizing: border-box;
        }
        textarea {
            min-height: 400px;
            resize: vertical;
        }
        button {
            background-color: #3498db;
            color: white;
            padding: 12px 20px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 16px;
            transition: background-color 0.3s ease;
            display: block;
            width: 100%;
        }
        button:hover {
            background-color: #2980b9;
        }
        button:disabled {
            background-color: #bdc3c7;
            cursor: not-allowed;
        }
        #statusMessage {
            margin-top: 20px;
            padding: 10px;
            border-radius: 5px;
            text-align: center;
            font-weight: bold;
        }
        .success {
            background-color: #e8f5e9; /* Light green */
            color: #2e7d32; /* Dark green */
            border: 1px solid #a5d6a7;
        }
        .error {
            background-color: #ffebee; /* Light red */
            color: #c62828; /* Dark red */
            border: 1px solid #ef9a9a;
        }
        .info {
            background-color: #e3f2fd; /* Light blue */
            color: #1565c0; /* Dark blue */
            border: 1px solid #90caf9;
        }
        .preview-container {
            margin-top: 30px;
            border-top: 1px solid #eee;
            padding-top: 20px;
        }
        iframe {
            width: 100%;
            height: 600px;
            border: 1px solid #ddd;
            border-radius: 5px;
            background-color: #fff;
        }

        /* Responsive layout for larger screens (PC) */
        @media (min-width: 992px) {
            .container {
                max-width: 1200px; /* Wider container on PC */
            }

            .content-wrapper {
                display: flex;
                align-items: stretch; /* Make columns same height */
                gap: 30px; /* Space between columns */
            }

            .input-panel {
                flex: 1;
                min-width: 0; /* Prevent flexbox overflow */
            }
            
            .preview-panel {
                flex: 1;
                min-width: 0; /* Prevent flexbox overflow */
                display: flex;
                flex-direction: column;
            }
            
            .preview-panel .preview-container {
                /* Reset mobile styles */
                margin-top: 0;
                border-top: none;
                padding-top: 0;
                
                /* Flex properties to fill space */
                flex-grow: 1;
                display: flex;
                flex-direction: column;
            }

            .preview-panel iframe {
                height: 100%; /* Override fixed height and fill available space */
            }

            .input-panel textarea {
                /* The preview will be tall, so the textarea should be as well */
                min-height: 800px; 
            }
        }

        .options-container {
            display: flex;
            align-items: center;
            margin-bottom: 20px;
        }
        .options-container input[type="checkbox"] {
            width: auto;
            margin-bottom: 0;
            margin-right: 8px;
        }
        .options-container label {
            margin-bottom: 0;
            font-weight: normal;
            user-select: none; /* Make label text non-selectable */
        }
        .selector-hint {
            font-size: 14px;
            color: #777;
            margin-top: -15px;
            margin-bottom: 15px;
            line-height: 1.5;
        }
        .selector-hint code {
            background-color: #f0f0f0;
            padding: 2px 4px;
            border-radius: 3px;
            color: #c7254e;
        }

        .selector-input-container {
            margin-bottom: 20px;
        }

        .input-with-button {
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .input-with-button input[type="text"] {
            margin-bottom: 0; /* Override default margin */
            flex-grow: 1; /* Take available space */
        }

        #suggestSelectorButton {
            width: auto; /* Shrink to content */
            padding: 10px 15px;
            font-size: 14px;
            line-height: 1;
            background-color: #0bab54;
            flex-shrink: 0; /* Prevent shrinking */
            position: relative;
            height: 40px; /* Match input height */
            box-sizing: border-box;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        #suggestSelectorButton:hover {
            background-color: #2c8a5b;
        }
        #suggestSelectorButton:disabled {
             background-color: #bdc3c7;
        }
        #suggestSelectorButton .loader {
            display: none; /* Hide loader by default */
        }

        /* Loader animation */
        .loader {
            border: 2px solid rgba(255, 255, 255, 0.3);
            border-top: 2px solid #fff;
            border-radius: 50%;
            width: 16px;
            height: 16px;
            animation: spin 1s linear infinite;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        .label-container {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        #uploadButton {
            background-color: #0bab54;
            padding: 6px 12px;
            font-size: 16px;
            width: auto;
            margin-bottom: 8px; /* Match label's margin */
            margin-right: 20px;
        }
        #uploadButton:hover {
            background-color: #95a5a6;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>智能HTML卡片转图片工具</h1>

        <div class="content-wrapper">
            <div class="input-panel">
                <div class="label-container">
                    <label for="htmlContent">HTML卡片内容:</label>
                    <button type-button id="uploadButton">从文件上传</button>
                    <input type="file" id="htmlFileInput" accept=".html,.htm,text/html" style="display:none;">
                </div>
                <textarea id="htmlContent" placeholder="在此处粘贴完整的HTML代码 (例如, 从<html>到</html>)..." spellcheck="false">{{ default_html }}</textarea>

                <div class="selector-input-container">
                    <label for="querySelector">CSS 选择器: 选择你要下载的卡片元素</label>
                    <div class="input-with-button">
                        <input type="text" id="querySelector" placeholder="可自动识别, 或手动输入... e.g., .card-container" value="">
                        <button type="button" id="suggestSelectorButton" title="自动识别选择器">
                            <span class="button-text">识别</span>
                            <span class="loader"></span>
                        </button>
                    </div>
                </div>
f
                <p class="selector-hint">
                    提示: 在预览区右键点击卡片 > 检查(Inspect) > 找到最外层的元素。
                    <br>
                    如果元素是 <code>&lt;div id="card"&gt;</code>, 则填 <code>#card</code>。
                    如果元素是 <code>&lt;div class="card"&gt;</code>, 则填 <code>.card</code>。
                </p>

                <div class="options-container">
                    <input type="checkbox" id="roundedCorners" name="roundedCorners" checked>
                    <label for="roundedCorners">添加圆角</label>
                </div>

                <button id="captureButton">生成并下载图片</button>

                <div id="statusMessage"></div>
            </div>
            
            <div class="preview-panel">
                <div class="preview-container">
                    <label for="previewFrame">HTML 预览:</label>
                    <iframe id="previewFrame" title="HTML Preview"></iframe>
                </div>
            </div>
        </div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const htmlContentInput = document.getElementById('htmlContent');
            const querySelectorInput = document.getElementById('querySelector');
            const roundedCornersCheckbox = document.getElementById('roundedCorners');
            const captureButton = document.getElementById('captureButton');
            const statusMessage = document.getElementById('statusMessage');
            const previewFrame = document.getElementById('previewFrame');
            const uploadButton = document.getElementById('uploadButton');
            const htmlFileInput = document.getElementById('htmlFileInput');
            const suggestSelectorButton = document.getElementById('suggestSelectorButton');

            uploadButton.addEventListener('click', () => htmlFileInput.click());

            htmlFileInput.addEventListener('change', (event) => {
                const file = event.target.files[0];
                if (!file) return;

                const reader = new FileReader();
                reader.onload = (e) => {
                    htmlContentInput.value = e.target.result;
                    // Trigger input event to update preview
                    htmlContentInput.dispatchEvent(new Event('input', { bubbles: true }));
                    showStatus(`已成功加载文件: ${file.name}`, 'success');
                };
                reader.onerror = () => {
                    showStatus(`读取文件失败: ${file.name}`, 'error');
                };
                reader.readAsText(file);
                
                // Reset file input to allow uploading the same file again
                htmlFileInput.value = '';
            });

            // --- Auto-suggest selector logic ---

            let debounceTimer;
            const suggestSelector = async () => {
                const htmlContent = htmlContentInput.value.trim();
                if (!htmlContent) {
                    querySelectorInput.value = '';
                    return;
                }

                const buttonText = suggestSelectorButton.querySelector('.button-text');
                const loader = suggestSelectorButton.querySelector('.loader');

                buttonText.style.display = 'none';
                loader.style.display = 'inline-block';
                suggestSelectorButton.disabled = true;

                try {
                    const response = await fetch('/api/suggest_selector', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({ html_content: htmlContent }),
                    });

                    const data = await response.json();
                    if (response.ok && data.success) {
                        querySelectorInput.value = data.selector;
                        showStatus('已自动识别CSS选择器。', 'success');
                    } else {
                        const errorMsg = data.error ? `识别失败: ${data.error}` : '自动识别选择器失败。';
                        showStatus(errorMsg, 'error');
                    }
                } catch (err) {
                    console.error('Suggest selector error:', err);
                    showStatus(`自动识别请求失败: ${err.message}`, 'error');
                } finally {
                    buttonText.style.display = 'inline-block';
                    loader.style.display = 'none';
                    suggestSelectorButton.disabled = false;
                }
            };

            const debouncedSuggestSelector = () => {
                clearTimeout(debounceTimer);
                debounceTimer = setTimeout(suggestSelector, 500); // 500ms delay
            };
            
            suggestSelectorButton.addEventListener('click', suggestSelector);
            htmlContentInput.addEventListener('input', () => {
                // Update preview instantly
                try {
                    const doc = previewFrame.contentWindow.document;
                    doc.open();
                    doc.write(htmlContentInput.value);
                    doc.close();
                } catch (e) {
                    console.error("Error updating preview:", e);
                    previewFrame.contentWindow.document.body.innerHTML = "<p style='color:red;'>无法加载预览，HTML可能存在错误。</p>";
                }
                
                // Debounce selector suggestion
                debouncedSuggestSelector();
            });

            // Initial load for default content
            if (htmlContentInput.value) {
                const doc = previewFrame.contentWindow.document;
                doc.open();
                doc.write(htmlContentInput.value);
                doc.close();
                // Also suggest selector for default content
                suggestSelector();
            }

            captureButton.addEventListener('click', async () => {
                const htmlContent = htmlContentInput.value.trim();
                const selector = querySelectorInput.value.trim();
                const addRoundedCorners = roundedCornersCheckbox.checked;

                if (!htmlContent) {
                    showStatus('请输入HTML内容。', 'error');
                    return;
                }
                if (!selector) {
                    showStatus('请输入CSS选择器。', 'error');
                    return;
                }

                showStatus('正在生成图片，请稍候...', 'info');
                captureButton.disabled = true;

                try {
                    const response = await fetch('/api/process_html_and_capture', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                        },
                        body: JSON.stringify({ 
                            html_content: htmlContent, 
                            selector: selector,
                            add_rounded_corners: addRoundedCorners
                        }),
                    });

                    if (response.ok && response.headers.get('Content-Type') === 'image/png') {
                        const blob = await response.blob();
                        const url = window.URL.createObjectURL(blob);
                        const a = document.createElement('a');
                        a.style.display = 'none';
                        a.href = url;
                        // 从Content-Disposition获取文件名，如果存在的话
                        const disposition = response.headers.get('Content-Disposition');
                        let filename = 'captured_image.png'; // 默认文件名
                        if (disposition && disposition.indexOf('attachment') !== -1) {
                            const filenameRegex = /filename[^;=\n]*=((['"])(?:\\.|[^\"\n])*?\2|[^;\n]*)/;
                            const matches = filenameRegex.exec(disposition);
                            if (matches != null && matches[1]) {
                                filename = matches[1].replace(/['"]/g, '');
                            }
                        }
                        a.download = filename;
                        document.body.appendChild(a);
                        a.click();
                        window.URL.revokeObjectURL(url);
                        showStatus('图片已成功下载！', 'success');
                    } else {
                        // 尝试解析JSON错误信息
                        const errorData = await response.json().catch(() => null);
                        if (errorData && errorData.error) {
                             let errorMsg = `图片生成失败: ${errorData.error}`;
                             if (errorData.details) {
                                errorMsg += ` <br>详细信息: ${formatErrorDetails(errorData.details)}`;
                             }
                            showStatus(errorMsg, 'error');
                        } else {
                            showStatus(`图片生成失败，服务器状态: ${response.status}`, 'error');
                        }
                    }
                } catch (err) {
                    console.error('Fetch error:', err);
                    showStatus(`请求失败: ${err.message}`, 'error');
                }
                captureButton.disabled = false;
            });

            function showStatus(message, type) {
                statusMessage.innerHTML = message; // Use innerHTML to render <br>
                statusMessage.className = type; // 'success', 'error', or 'info'
                statusMessage.style.display = 'block';
            }
            
            function formatErrorDetails(details) {
                // 将换行符替换为<br>以便在HTML中正确显示
                // 并对HTML特殊字符进行转义以防止XSS
                if (typeof details !== 'string') {
                    details = JSON.stringify(details, null, 2);
                }
                return details.replace(/&/g, '&amp;')
                              .replace(/</g, '&lt;')
                              .replace(/>/g, '&gt;')
                              .replace(/\n/g, '<br>');
            }
        });
    </script>
</body>
</html> 